package nl.fw.yapool.examples;

import java.util.List;

import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.Persistence;
import javax.persistence.Query;

import nl.fw.yapool.examples.entities.T;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * Demonstrates the use of the JPA layer in combination with Hibernate 4 and SqlPool.
 * JPA/Hibernate is configured in META-INF/persistence.xml.
 * The class {@link Hib4JpaCProvider} is used to configure a SqlPool using the persistence configuration.
 * The example has the following output: <pre>{@literal
10:04:063 [main] INFO yapool.example.hib4jpa - Starting ExampleHib4Jpa
10:04:302 [main] INFO org.hibernate.annotations.common.Version - HCANN000001: Hibernate Commons Annotations {4.0.2.Final}
10:04:310 [main] INFO org.hibernate.Version - HHH000412: Hibernate Core {4.2.10.Final}
10:04:313 [main] INFO org.hibernate.cfg.Environment - HHH000206: hibernate.properties not found
10:04:315 [main] INFO org.hibernate.cfg.Environment - HHH000021: Bytecode provider name : javassist
10:04:603 [main] INFO org.hibernate.service.jdbc.connections.internal.ConnectionProviderInitiator - HHH000130: Instantiating explicit connection provider: nl.fw.yapool.examples.Hib4JpaCProvider
10:04:615 [main] INFO yapool.example.hib4jpa.cp - SqlPool configured for Hibernate4Jpa example, using JDBC URL jdbc:hsqldb:mem:test
10:05:028 [main] INFO org.hibernate.dialect.Dialect - HHH000400: Using dialect: org.hibernate.dialect.HSQLDialect
10:05:184 [main] INFO org.hibernate.hql.internal.ast.ASTQueryTranslatorFactory - HHH000397: Using ASTQueryTranslatorFactory
10:05:485 [main] INFO org.hibernate.tool.hbm2ddl.SchemaExport - HHH000227: Running hbm2ddl schema export
10:05:487 [main] DEBUG org.hibernate.SQL - drop table t if exists
10:05:487 [main] DEBUG org.hibernate.SQL - create table t (id bigint generated by default as identity (start with 1), name varchar(255), primary key (id))
10:05:488 [main] INFO org.hibernate.tool.hbm2ddl.SchemaExport - HHH000230: Schema export complete
10:05:497 [main] INFO org.hibernate.engine.transaction.internal.TransactionFactoryInitiator - HHH000268: Transaction strategy: org.hibernate.engine.transaction.internal.jdbc.JdbcTransactionFactory
10:05:608 [main] DEBUG org.hibernate.SQL - insert into t (id, name) values (default, ?)
10:05:615 [main] TRACE org.hibernate.type.descriptor.sql.BasicBinder - binding parameter [1] as [VARCHAR] - Donald Duck
10:05:627 [main] INFO yapool.example.hib4jpa - Donald ID: 1
10:05:656 [main] DEBUG org.hibernate.SQL - select id from t where name like ?
10:05:659 [main] TRACE org.hibernate.type.descriptor.sql.BasicBinder - binding parameter [1] as [VARCHAR] - %Duck
10:05:664 [main] TRACE org.hibernate.type.descriptor.sql.BasicExtractor - Found [1] as column [ID]
10:05:666 [main] INFO yapool.example.hib4jpa - Queryied ID: 1
10:05:666 [main] INFO yapool.example.hib4jpa - Closing JPA.
10:05:668 [main] INFO org.hibernate.tool.hbm2ddl.SchemaExport - HHH000227: Running hbm2ddl schema export
10:05:668 [main] DEBUG org.hibernate.SQL - drop table t if exists
10:05:669 [main] INFO org.hibernate.tool.hbm2ddl.SchemaExport - HHH000230: Schema export complete
10:05:670 [main] INFO yapool.example.hib4jpa.cp - SqlPool closed.
10:05:670 [main] INFO yapool.example.hib4jpa - Finished ExampleHib4Jpa
}</pre>
 * @author Fred
 *
 */
public class ExampleHib4Jpa {

	public static final String LOG_CATEGORY = "yapool.example.hib4jpa";

	static {
		// Ensure Hibernate logger logs over slf4j 
		System.setProperty("org.jboss.logging.provider", "slf4j");
		
		// Uncomment following statement to see when Hibernate acquires and releases a connection from the pool.
		// Hib4JpaCProvider.logPoolEvents = true;
	}

	private static final Logger log = LoggerFactory.getLogger(LOG_CATEGORY);
	
	public static void main(String[] args) {

		log.info("Starting " + ExampleHib4Jpa.class.getSimpleName());
		ExampleHib4Jpa ev = new ExampleHib4Jpa();
		try {
			ev.demonstrate();
		} catch (Exception e) {
			log.error("Hib4Jpa example failed to run.", e);
		}
		log.info("Finished " + ExampleHib4Jpa.class.getSimpleName());
	}
	
	private EntityManagerFactory emf;
	private EntityManager em;
	
	public void demonstrate() throws Exception {
		
		try {
			
			// This will start Hibernate, load settings from META-INF/persistence.xml
			// which in turn starts the pool via the Hib4JpaCProvider class.
			emf = Persistence.createEntityManagerFactory("Hib4Jpa");
			em = emf.createEntityManager();
			T t = new T();
			t.setName("Donald Duck");
			em.getTransaction().begin();
			em.persist(t);
			em.getTransaction().commit();
			// The connection is released after commit by the entity-manager due to the persistence setting:
			// hibernate.connection.release_mode=after_transaction
			log.info("Donald ID: " + t.getId());
			Query q = em.createNativeQuery("select id from t where name like ?");
			q.setParameter(1, "%Duck");
			List<?> result = q.getResultList();
			log.info("Queryied ID: " + result.get(0));
			
		} catch (Exception e) {
			e.printStackTrace();
		} finally {
			close();
		}
	}
	
	private void close() {
		
		log.info("Closing JPA.");
		if (em != null) {
			em.close();
			em = null;
		}
		if (emf != null) {
			// This will also close the pool.
			emf.close();
			emf = null;
		}
	}
	
}
